/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.ts;

import edu.yonsei.iwb.di.ESService;
import edu.yonsei.iwb.ts.index.TSIndexFields;
import edu.yonsei.iwb.ts.model.ObjectNode;
import edu.yonsei.iwb.ts.model.Triple;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.OrFilterBuilder;

/**
 *
 * @author dk
 */
public class TSSearch {

    private static TransportClient client;
    private static String[] indices;
    private static int size = 100000;
    private Logger logger = Logger.getLogger(TSSearch.class);

    public TSSearch() {
        try {
            this.indices = new String[]{"_all"};
            this.client = ESService.openTransportClient();
            this.client.admin().cluster().health(new ClusterHealthRequest("_all").waitForYellowStatus().timeout("1s")).actionGet();
        } catch (ElasticsearchException ese) {
            logger.error(ese.getCause());
        }
    }

    public TSSearch(String[] indexList) {
        try {
            this.indices = indexList;
            this.client = ESService.openTransportClient();
            this.client.admin().cluster().health(new ClusterHealthRequest("_all").waitForYellowStatus().timeout("1s")).actionGet();
        } catch (ElasticsearchException ese) {
            logger.error(ese.getCause());
        }
    }

    public static ArrayList<String> listSubjectResource(String predicate, String object) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);

        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
        FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
        FilterBuilder fbf = FilterBuilders.andFilter().add(fbp).add(fbo);

        srb.setPostFilter(fbf);
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildResultResourceSet(sr, TSIndexFields.SUBJECT);
    }
    
    public static ArrayList<String> listSubjectResource(String predicate) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);

        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
        srb.setPostFilter(fbp);
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildResultResourceSet(sr, TSIndexFields.SUBJECT);
    }

    public static ArrayList<ObjectNode> listObjectNode(String subject, String predicate) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);
        FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
        FilterBuilder fbf = FilterBuilders.andFilter().add(fbp).add(fbo);
        srb.setPostFilter(fbf);
        srb.setSize(size);
        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildResultObjectSet(sr);
    }
    
    public static ArrayList<ObjectNode> listObjectNode(String predicate) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);        
        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);        
        srb.setPostFilter(fbp);
        srb.setSize(size);
        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildResultObjectSet(sr);
    }

    public static ArrayList<String> listPredicateResource(String subject, String object) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);

        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
        FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
        FilterBuilder fbf = FilterBuilders.andFilter().add(fbp).add(fbo);

        srb.setPostFilter(fbf);
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildResultResourceSet(sr, TSIndexFields.PREDICATE);
    }
    
    public static ArrayList<ObjectNode> listObjectResourceByORsubjectsAndProperty(ArrayList<String> subjects, String prop) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);
        
        OrFilterBuilder fbf = FilterBuilders.orFilter();
        for (int i = 0; i < subjects.size(); i++) {
            String subject = subjects.get(i);
            FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
            fbf.add(fbp);
        }
        
        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, prop);        
        FilterBuilder fbl = FilterBuilders.andFilter().add(fbf).add(fbp);
        srb.setPostFilter(fbl);        
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildDistinctResultObjectSet(sr);
    }
    
    public static ArrayList<String> listSubjectResourceByORobjectsAndProperty(String prop, ArrayList<String> objects) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);
        
        OrFilterBuilder fbf = FilterBuilders.orFilter();
        for (int i = 0; i < objects.size(); i++) {
            String object = objects.get(i);
            FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
            fbf.add(fbp);
        }
        
        FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, prop);        
        FilterBuilder fbl = FilterBuilders.andFilter().add(fbf).add(fbp);        
        srb.setPostFilter(fbl);
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildDistinctResultResourceSet(sr, TSIndexFields.SUBJECT);
    }
    
    public static ArrayList<String> listPredicateResourceByORsubjects(ArrayList<String> subjects) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);
        
        OrFilterBuilder fbf = FilterBuilders.orFilter();
        for (int i = 0; i < subjects.size(); i++) {
            String subject = subjects.get(i);
            FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
            fbf.add(fbp);
        }
        
        srb.setPostFilter(fbf);
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildDistinctResultResourceSet(sr, TSIndexFields.PREDICATE);
    }
    
    public static ArrayList<String> listDistinctPredicateResourceByORobjects(ArrayList<String> objects) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);
        
        OrFilterBuilder fbf = FilterBuilders.orFilter();
        for (int i = 0; i < objects.size(); i++) {
            String object = objects.get(i);
            FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
            fbf.add(fbp);
        }
        
        srb.setPostFilter(fbf);
        srb.setSize(size);

        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildDistinctResultResourceSet(sr, TSIndexFields.PREDICATE);
    }
    
     public static ArrayList<Triple> listTriple(String subject, String predicate, String object) throws IOException {
        SearchRequestBuilder srb = client.prepareSearch(indices);        
        if (subject == null) {
            if (predicate == null) {
                if (object == null) {
                    // all null
                    System.out.println("-- all null");
                }else{
                    // only object
                    FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
                    srb.setPostFilter(fbo);
                }
            } else {
                // predicate exists
                if (object == null) {
                    // only predicate
                    FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
                    srb.setPostFilter(fbp);                    
                }else{
                    //predicate and object exist                    
                    FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
                    FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
                    FilterBuilder fbf = FilterBuilders.andFilter().add(fbo).add(fbp);
                    srb.setPostFilter(fbf);
                }
            }
        } else if (predicate == null) {
            // subject exists
            if (object == null) {
                // only subject
                FilterBuilder fbs = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
                srb.setPostFilter(fbs);
            } else {
                // subject and object exist
                FilterBuilder fbs = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
                FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
                FilterBuilder fbf = FilterBuilders.andFilter().add(fbs).add(fbo);
                srb.setPostFilter(fbf);
            }
        } else if (object == null) {
            //only object is null
            FilterBuilder fbs = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
            FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
            FilterBuilder fbf = FilterBuilders.andFilter().add(fbs).add(fbp);
            srb.setPostFilter(fbf);
        } else {
            //all values exist
            FilterBuilder fbs = FilterBuilders.termFilter(TSIndexFields.SUBJECT, subject);
            FilterBuilder fbp = FilterBuilders.termFilter(TSIndexFields.PREDICATE, predicate);
            FilterBuilder fbo = FilterBuilders.termFilter(TSIndexFields.OBJECT, object);
            FilterBuilder fbf = FilterBuilders.andFilter().add(fbs).add(fbp).add(fbo);
            srb.setPostFilter(fbf);
        }
        
        srb.setSize(size);
        SearchResponse sr = srb.execute().actionGet();
        return TSSearchResultBuilder.buildResultOfAllvalue(sr);
    }

//    public void setMergedFilter(){
//        if(this.operator.equals("AND")){
//            System.out.println("set merged filter");
//            FilterBuilders.andFilter().add(this.leftFilter).add(this.rightFilter);
//        }else{
//            System.out.println("set merged filter");
//            FilterBuilders.orFilter().add(this.leftFilter).add(this.rightFilter);
//        }
//    }
    private void setIndicies(ArrayList<String> fromList) {
        ArrayList<String> indices = new ArrayList();
        for (int i = 0; i < fromList.size(); i++) {
            String index = fromList.get(i);
            boolean isExists = this.client.admin().indices().prepareExists(index).execute().actionGet().isExists();
            if (isExists) {
                indices.add(index);
            }
        }
        if (indices.isEmpty()) {
            this.indices = new String[]{"_all"};
        } else {
            this.indices = indices.toArray(new String[indices.size()]);
        }
    }
    
    public static void setINDEX(ArrayList indexnames){
        indices = new String[indexnames.size()];
        for (int i = 0; i < indexnames.size(); i++) {
            String in = indexnames.get(i).toString();
            indices[i] = in;            
        }        
    }
        
}
